import { CallHandler, ExecutionContext, Injectable, NestInterceptor } from '@nestjs/common'
import { plainToInstance } from 'class-transformer'
import { Request } from 'express'
import { map, Observable } from 'rxjs'

@Injectable()
export class SerializeInterceptor implements NestInterceptor {
  constructor(private dto: any) {}
  // CallHandler 接口实现了 handle() 方法，可以在拦截器中的某个时刻使用该方法来调用路由处理方法。
  // 在实现 intercept() 方法时没有调用 handle() 方法，则根本不会执行路由处理方法。所以handle()是必需的
  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    // 1.获取请求对象
    /* context：指向当前请求上下文的对象 
    switchToHttp()：允许从 ExecutionContext 中切换到 HTTP 上下文，这样就可以访问 HTTP 请求和响应对象。
    getRequest<Request>()：该方法获取当前的 HTTP 请求对象，类型为 Request */
    const req = context.switchToHttp().getRequest<Request>()
    console.log('这里在拦截器执行之前', req)

    return next.handle().pipe(
      // 由于 handle() 方法返回一个 Observable，我们可以使用强大的 RxJS 操作符来进一步处理响应。
      // 1. pipe():用于将多个操作符串联在一起，来处理 Observable 数据流，
      // 可以在 pipe() 中使用各种操作符（如 map(), tap(), filter() 等）来对数据进行不同的操作。
      // 2.切面拦截（RxJS 操作符）
      // tap()：用来执行副作用操作，不会改变流中的数据，主要用于日志记录、监控、调试等场景。在拦截器中，
      // 可以用它来观察 HTTP 请求或响应，打印信息，而不影响流的后续处理。
      // 3. 响应映射（RxJS 操作符）
      // map()：用来转换 Observable 流中的数据。map 将响应对象赋值给新创建对象的 data 属性，然后将新对象返回给客户端。

      map((data: any) => {
        // console.log('这里在拦截器执行之后', data)
        // return data

        // import { plainToInstance } from 'class-transformer'
        return plainToInstance(this.dto, data, {
          // excludeExtraneousValues:true=>所有经过该interceptor的接口都需要设置Expose或Exclude
          // Expose：哪些字段需要暴露，Exclude：哪些字段不需要暴露
          excludeExtraneousValues: true
        })
      })
    )
  }
}
